require"manage"

module(...,package.seeall)

local smatch,schar = string.match,string.char
local function addparaver()
	nvm.set("paraver",nvm.get("paraver")+1)
end

local function deveventrsp(p,result,user)
	if p.id==protoair.RESET then
		user = {cb=function(result, param)
			if result then sys.restart(param) end
		end, para="SVR RESTART"}
	elseif p.id==protoair.POWEROFF then
		user = {cb=rtos.poweroff}
	end
	linkout.insertOutMsg(linkout.enTopic("deveventrsp/"..(smatch(p.topic,"deveventreq/(.+)") or "")),
						protoair.pack(protoair.DEVEVENTRSP,p.id,schar(result or 1)),
						1,user)
end

local function listpara(p,v)
	addparaver()
	for i=1,#p.val do
		log.info("linkin.listpara",v,i,p.val[i])
	end
	return nvm.set(v,p.val,"SVR")
end

local function award(p)
	addparaver()
	if nvm.get("totaleggs")~=p.total or nvm.get("finisheggs")~=p.finish or nvm.get("todayeggs")~=p.today then
		nvm.set("totaleggs",p.total,nil,false)
		nvm.set("finisheggs",p.finish,nil,false)
		nvm.set("todayeggs",p.today,nil,false)
		nvm.flush()
		sys.publish("AWARD_IND")
	end
	return true
end

local function setpara(p)	
	local procer,result = {
		[protoair.RPTFREQ] = "rptfreq",
		[protoair.CALLVOL] = "volume",
		[protoair.SILTIME] = {k=listpara,v="silentime"},
		[protoair.AWARD] = award,
		[protoair.NOTICE] = {k=listpara,v="notice"},
		[protoair.WHITENUMSWITCH] = "whitenumswitch",
		[protoair.DIALSWITCH] = "dial_disable",
	}
	if procer[p.cmd] then
		local typ = type(procer[p.cmd])
		if typ == "function" then
			result = procer[p.cmd](p)
		elseif typ == "table" then
			if type(procer[p.cmd].k) == "function" then
				result = procer[p.cmd].k(p,procer[p.cmd].v)
			else
				result = nvm.set(procer[p.cmd].k,procer[p.cmd].v,"SVR")
			end
		else
			addparaver()
			result = nvm.set(procer[p.cmd],p.val,"SVR")
		end

		if p.cmd == protoair.NOTICE and result then
			sys.publish('NOTICE_UPDATE_IND')
		end
	end
	linkout.insertOutMsg(linkout.enTopic("devpararsp/"..(smatch(p.topic,"devparareq/(.+)") or "")),
						protoair.pack(protoair.SETPARARSP,p.cmd,schar(result and 1 or 0)),
						1)
end

local function qryloc(p)
	deveventrsp(p)
	linkout.locReport(protoair.QRYPOS)
end

local function monitCb(result, num)
	if not result then return end
	sys.publish("SVR_MONIT_IND",num)
end
local function monit(p)
	deveventrsp(p,1,{cb=monitCb,para=#p.num > 0 and p.num[1] or ""})
end

local function restore(p)
	sys.publish("SVR_RESTORE_IND","SVR")
	deveventrsp(p)
end

local function ringon(p)
	sys.publish("SVR_RINGON_IND")
	deveventrsp(p)
end

local function takePhoto(p)
	sys.publish("SVR_TAKEPHOTO_IND")
	deveventrsp(p)
end

local function smpset(p)	
	local procer = {
		[protoair.DATETIME] = function() end,
		[protoair.SMSCENTERNUM] = function(p) nvm.set("smscenternum",p.num,"SVR") end,
		[protoair.SIMNUMRPT] = function() sys.publish("PARA_CHANGED_IND","smscenternum") end,
	}
	procer[p.cmd](p)
end

local function updateAward(p)
	if nvm.get("totaleggs")~=p.awardtotal or nvm.get("finisheggs")~=p.awardfinish or nvm.get("todayeggs")~=p.awardtoday then
		nvm.set("totaleggs",p.awardtotal,nil,false)
		nvm.set("finisheggs",p.awardfinish,nil,false)
		nvm.set("todayeggs",p.awardtoday,nil,false)
		nvm.flush()
		sys.publish("AWARD_IND")
	end
end
local function getpararsp(p)
	if p.paratyp==protoair.EGG then
		updateAward(p)
	end
end

local function qrypara(p)
	local procer,rsp = {
		[protoair.VER] = function() return _G.PROJECT.."_".._G.VERSION end,
		[protoair.DEVPARA] = function() sys.publish("DEVPARA_RPT_REQ") return schar(1) end,
	}
	if procer[p.val] then
		rsp = procer[p.val]()
	end
	if rsp then
		linkout.insertOutMsg(linkout.enTopic("deveventrsp/"..(smatch(p.topic,"deveventreq/(.+)"))),
						protoair.pack(protoair.DEVEVENTRSP,p.id,schar(p.val)..rsp),
						1)
	end
end

local function chatrcd(p)
	if p.dup then return end
	local typ,cid,mid,msgid = true
	if smatch(p.topic,"/single/stod/[&%w]+$") then
		mid,msgid = smatch(p.topic,"/([&%w]+)/[&%w]+/single/stod/([&%w]+)$")
		cid = mid
	elseif smatch(p.topic,"/group/[&%w]+/stod/[&%w]+$") then
		mid,cid,msgid = smatch(p.topic,"/([&%w]+)/[&%w]+/group/([&%w]+)/stod/([&%w]+)$")
		typ = false
	end
	log.info("linkin.chatrcd msgid",msgid)
	log.info("linkin.chatrcd",p.topic,typ,cid,mid,p.sn,p.total,p.cur,p.datyp,p.tmlen)
	manage.rcvrcd(typ,cid,mid,p.tm,p.sn,p.total,p.cur,p.datyp,p.tmlen,p.dat)
	if msgid then
		linkout.insertOutMsg(linkout.enTopic2("device","confirm",msgid),"")
	end
end

local function updpb(p)
	addparaver()
	--log.info("linkin.updpb",p.cmd,p.pbtyp,p.pid,p.phone,common.ucs2betogb2312(p.name or ""),p.icontyp,p.iconid,p.iconupd)
	local cmd,pb,typ,id,i,proc,del=p.cmd,nvm.get("contact"),p.pbtyp,p.pid
	if cmd==0 or cmd==2 then
		for i=1,#pb do
			if --[[pb[i].typ==typ and ]]id==pb[i].id then
				pb[i].typ=typ
				pb[i].phone = p.phone or {}
				pb[i].nm = common.ucs2betogb2312(p.name or "")
				pb[i].icontyp,pb[i].iconupd = p.icontyp,p.iconupd
				proc = true
			end
		end
		if not proc and cmd==0 then
			proc = true
			pb[#pb+1]={typ=typ,id=id,phone=p.phone,nm=common.ucs2betogb2312(p.name or ""),icontyp=p.icontyp,iconid=p.iconid,iconupd=p.iconupd}
		end
	elseif p.cmd==1 then
		for i=#pb,1,-1 do
			if id==pb[i].id then
				manage.delcht(id)
				table.remove(pb,i)
				proc,del = true,true
				end
		end
		proc = true
	end
	
	linkout.insertOutMsg(linkout.enTopic("updpbrsp/"..(smatch(p.topic,"updpbreq/(.+)") or "")),
						protoair.pack(protoair.UPDPBRSP,p.cmd,schar(proc and 1 or 0)))
	
	if proc then
		nvm.set("contact",pb,"SVR")
	end
end


local parasyncing,parasynver,parasyncpb
local function parasync(p)
	deveventrsp(p)
	if not p.paraver and not parasyncing then print("parasync err1") return end
	if p.paraver then
		parasynver = p.paraver
		parasyncpb = {}
		parasyncing = true
	end
	if p.pblist then
		if #p.pblist==0 then
			parasyncpb = {}
		else
			local i
			for i=1,#p.pblist do
				table.insert(parasyncpb,p.pblist[i])
			end
		end
	end
	if p.sil then
		nvm.set("silentime",p.sil,"SVR")
	end
	if p.awardtotal then
		updateAward(p)
	end
	if p.notice then
		nvm.set("notice",p.notice,"SVR")
	end
	if p.whitenumswitch then
		nvm.set("whitenumswitch",p.whitenumswitch,"SVR")
	end
	if p.dialswitch then
		nvm.set("dial_disable",p.dialswitch == 1,"SVR")
	end
	if p.synend then
		local oldpb,i,j,fnd = nvm.get("contact")
		for i=1,#oldpb do
			for j=1,#parasyncpb do
				if oldpb[i] and parasyncpb[j] and oldpb[i].id==parasyncpb[j].pid then
					fnd = true
					break
				end
			end
			if not fnd then manage.delcht(oldpb[i].id) end
		end
		
		oldpb = {}
		for i=1,#parasyncpb do
			oldpb[i]={typ=parasyncpb[i].pbtyp,id=parasyncpb[i].pid,phone=parasyncpb[i].phone,nm=common.ucs2betogb2312(parasyncpb[i].name or "")}
		end
		nvm.set("paraver",parasynver,nil,false)
		nvm.set("contact",oldpb,"SVR")
		parasyncing,parasynver,parasyncpb = nil
	end
end


local cmds = {
	[protoair.SETPARA] = setpara,
	[protoair.QRYLOC] = qryloc,
	[protoair.RESET] = deveventrsp,
	[protoair.MONIT] = monit,
	[protoair.POWEROFF] = deveventrsp,
	[protoair.RESTORE] = restore,
	[protoair.RINGON] = ringon,
	[protoair.SMPSET] = smpset,
	[protoair.GETPARARSP] = getpararsp,
	[protoair.QRYPARA] = qrypara,
	[protoair.CHATRCD] = chatrcd,
	[protoair.UPDPB] = updpb,
	[protoair.PARASYNC] = parasync,
	[protoair.TAKEPHOTO] = takePhoto,
}

function procMsg(mqttc)
	local r,data
	while true do
		r,data = mqttc:receive(2000)
		
		if r and data~="timeout" then
			log.info("linkin.procMsg",data.topic,string.tohex(data.payload))
			local packet = protoair.unpack(data.payload)
			if packet and packet.id and cmds[packet.id] then
				packet.topic = data.topic
				cmds[packet.id](packet)
				if linkout.waitForSend() then return true end
			end
		else
			break
		end
	end
	
	return data=="timeout" or r
end
